﻿using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.IO;
using System.IO.IsolatedStorage;
using System.Linq;
using System.Text;
using System.Threading;
using System.Windows.Forms;
using System.Diagnostics;

namespace NewKataminoSolver
{
    public partial class Katamino : Form
    {
        public Katamino()
        {
            InitializeComponent();
        }
        private void startButton_Click(object sender, EventArgs e)
        {
            // Always runs on UI thread

            // disable 'Start' button
            this.startButton.Enabled = false;

            // Prepare work. Setting UI variables in its own thread is thread safe
            solutionNr = 0;

            // do work in seperate thread
            backgroundWorker1.RunWorkerAsync();
            // invokes backgroundWorker1_DoWork

            // click function finishes, with process in background
            // form is responsive with startButton disabled
            // background worker will do work and update form via delegates:
            // backgroundWorker1_ProgressChanged
        }
        private void documentationButton_Click(object sender, EventArgs e)
        {
            KataminoGraph kg = new KataminoGraph(this, 72, 48);

            Penta[][] p = new Penta().Variations(); // in normalized form..

            for (int p1 = 0; p1 < p.Length; p1++)
            {
                for (int p2 = 0; p2 < p[p1].Length; p2++)
                {
                    kg.DrawColorPentaAt(p1 + 1, p[p1][p2], 6 * p1, 6 * p2);
                }
            }
            pictureBox1.Image = kg._bm;
            pictureBox1.Refresh();
            kg._bm.Save(@"kataminos2.gif", System.Drawing.Imaging.ImageFormat.Gif);
        }
        private void cancelButton_Click(object sender, EventArgs e)
        {
            // Runs on the UI thread, sets other thread's CancellationPending true
            backgroundWorker1.CancelAsync();
        }
        private void exitButton_Click(object sender, EventArgs e)
        {
            Application.Exit();
        }

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            // This is executed on a sepate thread
            Debug.Assert(InvokeRequired,
                "Threading Error",
                "This thread should not run on UI thread");

            KataminoController.Calculate(this, e); // pass the Katamino form
        }
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            Debug.Assert(!InvokeRequired,
                "Threading Error",
                "This thread should run on UI thread");

            // Raised on UI thread when DoWork calls ReportProgress
            // Progress is reported on each Katamino solution
            this.progressBar1.Value = e.ProgressPercentage;
            this.progressBar2.Value = (progressBar2.Value + 5) % 105;
        }
        private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
        {
            // Raised on UI thread when DoWork finishes
            Debug.Assert(!InvokeRequired,
                "Threading Error",
                "This thread should run on UI thread");

            if (e.Cancelled) { } // MessageBox.Show("Cancelled!");
            else if (e.Error != null) { } // MessageBox.Show("Error!");
            else { } // MessageBox.Show("Het resultaat is: " + e.Result);
            startButton.Enabled = true;

            // look finished wrt progress bars upon completion
            progressBar1.Value = 100;
            progressBar2.Value = 100;
        }

        public Size ImageSize()
        {
            return this.pictureBox1.Size;
        }
        public BackgroundWorker KataminoBackgroundWorker()
        {
            return this.backgroundWorker1;
        }

        // To update the picturebox on the UI thread:
        //  Check if it runs on the UI thread by !InvokeRequired
        public void UpdatePicture(Bitmap bm)
        {
            if (!this.InvokeRequired)
            {
                pictureBox1.Image = bm;
                pictureBox1.Refresh();

                solutionNr++;
                String fileName = "katamino_solution_" + solutionNr.ToString() + ".gif";
                saveStrategy.SaveBitmap(bm, fileName);
                // bm.Save(fileName, System.Drawing.Imaging.ImageFormat.Gif);
            }
            else
            {
                this.Invoke(new MethodInvoker_TakesBitmap(UpdatePicture), new object[] { bm });
            }
        }
        //  Delegate to pass to Invoke
        public delegate void MethodInvoker_TakesBitmap(Bitmap bm);

        private static int solutionNr = 0;

        private void pictureBox1_Paint(object sender, PaintEventArgs e)
        {
            // dummy paint function, helps rendering in multi-threaded environment!
            // It executes after rendering is complete before returning control
            // to the background worker.
            // [Otherwise, the control is sometimes returned before rendering complete]
        }

        // Strategy Design Pattern: select one of those (dynamically?!)
        ISaveBitmap saveStrategy = new FileSaveStrategy();
        // ISaveBitmap saveStrategy = new IsolatedStoreSaveStrategy();
        // Make this List<ISaveBitmap> ?
    }

    // Strategy Design Pattern to make it easy to select between store methods.
    // Or create a iteratable List<ISaveBitmap>, to allow multiple save strategies.
    interface ISaveBitmap
    {
        void SaveBitmap(Bitmap bm, string fileName);
    }
    class FileSaveStrategy : ISaveBitmap
    {   // pro: easy access, con: Code Access Security (will not run in guest account)
        public void SaveBitmap(Bitmap bm, string fileName)
        {
            bm.Save(fileName, System.Drawing.Imaging.ImageFormat.Gif);
        }
    }
    class IsolatedStoreSaveStrategy : ISaveBitmap
    {   // pro: Code Access Security, con: Isolated Storage needs browser in app to access
        static IsolatedStorageFile machineStorage =
            IsolatedStorageFile.GetMachineStoreForAssembly();

        public void SaveBitmap(Bitmap bm, string fileName)
        {
            IsolatedStorageFileStream fileStream = new IsolatedStorageFileStream(fileName, FileMode.Create);
            bm.Save(fileStream, System.Drawing.Imaging.ImageFormat.Gif);
        }
    }
}
